<script setup lang="ts">
import { reduce } from 'lodash-es'
import { computed, type PropType, type VNode } from 'vue'
import RenderVNode from '@/components/RenderVnode'
import type { TextComponentProps, ImageComponentProps } from '@/defaultProps'
import { mapPropsToForms, type PropsToForm } from '@/propsMap'

const props = defineProps({
  props: {
    type: Object as PropType<TextComponentProps & ImageComponentProps>,
    required: true
  }
})
const emits = defineEmits(['change'])

interface FormProps {
  component: string
  subComponent?: string
  value: string
  // 组件的属性
  extraProps?: { [key: string]: any }
  // 说明
  text?: string
  // 子组件的一些属性
  options?: { text: string | VNode; value: any }[]
  // value 的字段名可以替换
  valueProp: string
  //修改完成value后的事件的名称
  eventName: string
  // 修改value的事件,可以有多个事件key是事件名称
  //   <!-- 对象语法 -->
  // <button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
  events: { [key: string]: (e: any) => void }
}
type FormPropss = {
  [p in keyof (TextComponentProps & ImageComponentProps)]?: PropsToForm
}

const finalProps = computed(() => {
  return reduce(
    props.props,
    (result, value, key) => {
      const newKey = key as keyof FormPropss
      const item = mapPropsToForms[newKey]
      if (item) {
        const { valueProp = 'value', eventName = 'change', initialTransform, afterTransform } = item

        item.valueProp = item.valueProp ? item.valueProp : 'value'
        const newItem: FormProps = {
          ...item,
          value: initialTransform ? initialTransform(value) : value,
          valueProp: valueProp,
          eventName: eventName,
          events: {
            [eventName]: (e: any) => {
              emits('change', { key, value: afterTransform ? afterTransform(e) : e })
            }
          }
        }
        result[newKey] = newItem
      }
      return result
    },
    {} as { [p in keyof TextComponentProps]: FormProps }
  )
})
</script>

<template>
  <div class="props-table" v-for="(item, index) in finalProps" :key="index">
    <span class="text">{{ item?.text }}</span>
    <div class="component">
      <component
        :is="item?.component"
        :[item?.valueProp]="item?.value"
        v-bind="item?.extraProps"
        v-on="item.events"
      >
        <template v-if="item?.subComponent">
          <component
            v-for="(item1, index1) in item.options"
            :key="index1"
            :is="item?.subComponent"
            :value="item1.value"
          >
            <RenderVNode :v-node="item1.text"></RenderVNode>
          </component>
        </template>
      </component>
    </div>
  </div>
</template>

<style scoped lang="scss">
.props-table {
  display: flex;
  padding-left: 4px;
  margin-bottom: 16px;
  .text {
    width: 3em;
  }
  .component {
    padding-left: 8px;
    box-sizing: border-box;
    width: calc(100% - 4em);
  }
}
</style>
